#include "imagecanvas.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QImageReader>
#include <QDesktopServices>
#include <QImageWriter>
#include <QDirIterator>

ImageCanvas::ImageCanvas(QDeclarativeItem *parent) :
    QDeclarativeItem(parent), m_color(Qt::white),m_penX(0),m_penY(0),m_penWidth(1),m_aspect(Qt::IgnoreAspectRatio),
    m_transformMode(Qt::FastTransformation),m_penEnabled(false),m_saveInProgress(false),m_drawType(DrawPen)
{
    setFlag(QGraphicsItem::ItemHasNoContents,false);
}

void ImageCanvas::paint(QPainter* painter, const QStyleOptionGraphicsItem* styleOption, QWidget* widget)
{
    qDebug() << __PRETTY_FUNCTION__ << " image: " << m_editImage.isNull() << " save: " << m_saveInProgress;
    if(m_editImage.isNull())
        return;

    if(m_saveInProgress)
        return;

    bool aa = painter->testRenderHint(QPainter::Antialiasing);

    if(smooth()){
        painter->setRenderHint(QPainter::Antialiasing,true);
    }

    if(width()!=m_editImage.width() || height()!=m_editImage.height()){
        painter->drawPixmap(QRectF(this->x(),this->y(),this->width(),this->height()),
                            m_editImage,
                            m_editImage.rect());
    }else{
        painter->drawPixmap(QPoint(0,0),m_editImage);
    }   

    if(smooth()){
        painter->setRenderHint(QPainter::Antialiasing,aa);
    }
}

void ImageCanvas::updateImage()
{
    qDebug() << __PRETTY_FUNCTION__;
    if(m_penEnabled){
        QPen pen(m_color,m_penWidth,Qt::SolidLine,m_penCapStyle,m_penJoinStyle);

        QScopedPointer<QPainter> painter(new QPainter());

        painter->begin(&m_editImage);
        if(smooth()){
            painter->setRenderHint(QPainter::Antialiasing,true);
        }

        qreal scaleX = m_editImage.width()/this->width();
        qreal scaleY = m_editImage.height()/this->height();

        // store point also with original size,
        qreal storeScaleX = m_originalSourceSize.width()/this->width();
        qreal storeScaleY = m_originalSourceSize.height()/this->height();

        QPointF point;
        if(m_editImage.size()!=m_sourceSize){
            point = QPointF(m_penX*scaleX,m_penY*scaleY);
        }else{
            point = QPointF(m_penX,m_penY);
        }

        CanvasPoint cpoint;
        cpoint.type = m_drawType;
        painter->setPen(pen);


        switch(m_drawType){
        case DrawPen:{
            cpoint.pen  = pen;
            cpoint.start = point;
            m_penPointsScreen.append(cpoint);
            painter->drawPoint(point);

            CanvasPoint cstore;
            cstore.pen = pen;
            cstore.start = QPointF(m_penX*storeScaleX,m_penY*storeScaleY);
            cstore.type = m_drawType;
            m_penPoints.append(cstore);
        }break;
        case DrawLine:{
            if(m_penPointsScreen.isEmpty()){
                cpoint.pen  = pen;
                cpoint.start = point;
                m_penPointsScreen.append(cpoint);

                CanvasPoint cstore;
                cstore.pen = pen;
                cstore.start = QPointF(m_penX*storeScaleX,m_penY*storeScaleY);
                cstore.type = m_drawType;
                m_penPoints.append(cstore);
            }else{
                if(m_penPointsScreen.last().type==DrawLine){
                    if(m_penPointsScreen.last().end.isNull()){
                        m_penPointsScreen.last().end = point;
                        painter->drawLine(m_penPointsScreen.last().start,m_penPointsScreen.last().end);
                        m_penPoints.last().end = QPointF(m_penX*storeScaleX,m_penY*storeScaleY);
                    }else{
                        cpoint.start = m_penPointsScreen.last().end;
                        cpoint.end = point;
                        cpoint.pen = pen;
                        m_penPointsScreen.append(cpoint);
                        painter->drawLine(m_penPointsScreen.last().start,m_penPointsScreen.last().end);

                        CanvasPoint cstore;
                        cstore.pen = pen;
                        cstore.start = m_penPoints.last().end;
                        cstore.end = QPointF(m_penX*storeScaleX,m_penY*storeScaleY);
                        cstore.type = m_drawType;
                        m_penPoints.append(cstore);
                    }
                }
                if(m_penPointsScreen.last().type==DrawPen){
                    cpoint.start = m_penPointsScreen.last().start;
                    cpoint.end = point;
                    cpoint.pen = pen;
                    m_penPointsScreen.append(cpoint);
                    painter->drawLine(m_penPointsScreen.last().start,m_penPointsScreen.last().end);

                    CanvasPoint cstore;
                    cstore.pen = pen;
                    cstore.start = m_penPoints.last().start;
                    cstore.end = QPointF(m_penX*storeScaleX,m_penY*storeScaleY);
                    cstore.type = m_drawType;
                    m_penPoints.append(cstore);
                }
            }
        }break;
        default:break;
        }

        painter->end();
    }
    update();
}

void ImageCanvas::setUnderneathImage(QUrl filename)
{
    m_underneathImageFilename=filename;
    QFile file(m_underneathImageFilename.toLocalFile());
    if(file.open(QIODevice::ReadOnly)){
        QScopedPointer<QImageReader> reader(new QImageReader(&file));
        m_sourceImage = reader->read();

        m_penPoints.clear();
        m_penPointsScreen.clear();

        if(reader->error()|| m_sourceImage.isNull()){
            m_error = LoadError;
            m_errorString = reader->errorString();
            qDebug() << "error: " << reader->error() << " str: " << reader->errorString();
            emit error();
        }else{
            m_editImage = QPixmap::fromImage(m_sourceImage);
            m_sourceSize = m_editImage.size();
            m_originalSourceSize = m_sourceImage.size();
            this->setImplicitHeight(m_editImage.height());
            this->setImplicitWidth(m_editImage.width());
            this->update();
            m_error = NoError;
            emit sourceSizeChanged();
            emit originalSourceSizeChanged();
        }
    }else{
        m_error = LoadError;
        m_errorString = file.errorString();
    }
    emit underneathImageChanged();
}

void ImageCanvas::createEmpty(int width,int height)
{
    if(width>0&&height>0){
        m_editImage = QPixmap(width,height);
        if(!m_editImage.isNull()){
            m_editImage.fill();
            m_sourceSize = m_editImage.size();
            m_originalSourceSize = m_sourceSize;
            this->setImplicitHeight(m_editImage.height());
            this->setImplicitWidth(m_editImage.width());
            this->update();
            m_error = NoError;
            m_sourceImage = m_editImage.toImage();
            emit sourceSizeChanged();
            emit originalSourceSizeChanged();
        }else{
            m_error = CreateError;
            emit error();
        }
    }
}

void ImageCanvas::save(QString filename)
{
    qDebug() << __PRETTY_FUNCTION__ << " pen: " << m_penPoints.isEmpty() << " image: " << m_sourceImage.isNull() << " filename: " << filename;
    m_error = SaveError;
    m_saveInProgress = true;
    m_penEnabled = false;
    if(!filename.isEmpty()){
        QString path(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
        qDebug() << "path: " << path;
        QString fn("e:/");
        fn.append( path.split('/',QString::SkipEmptyParts).last());
        fn.append("/");
        fn.append(filename);
        if(!fn.endsWith(".jpg"))
            fn.append(".jpg");

        QFile file(fn);
        file.remove();
        QImage tmp(m_sourceImage);

        QScopedPointer<QPainter> p(new QPainter());
        p->begin(&tmp);
        for(int i=0;i<m_penPoints.count();i++){
            CanvasPoint cpoint = m_penPoints.at(i);
            p->setPen(cpoint.pen);
            switch(cpoint.type){
            case DrawPen:{
                p->drawPoint(cpoint.start);
            }break;
            case DrawLine:{
                p->drawLine(cpoint.start,cpoint.end);
            }break;
            default:break;
            }
        }
        p->end();

        QScopedPointer<QImageWriter> w(new QImageWriter(fn));
        w->write(tmp);
        if(!w->error()){
            m_error = NoError;
        }
    }
    m_penEnabled = true;
    m_saveInProgress = false;
    emit saveChanged();
}

void ImageCanvas::setSourceSize(QSize size)
{
    m_sourceSize=size;
    emit sourceSizeChanged();
}


void ImageCanvas::undo()
{
    qDebug() << __PRETTY_FUNCTION__ << " pen: " << m_penPoints.isEmpty() << " image: " << m_sourceImage.isNull();
    if(!m_sourceImage.isNull() && !m_penPoints.isEmpty()){
        m_saveInProgress = true;

        QSize size = m_editImage.size();
        m_editImage = QPixmap::fromImage(m_sourceImage);
        m_penPoints.takeLast();        
        m_penPointsScreen.takeLast();
        QScopedPointer<QPainter> p(new QPainter());
        p->begin(&m_editImage);
        for(int i=0;i<m_penPoints.count();i++){
            CanvasPoint cpoint = m_penPoints.at(i);
            p->setPen(cpoint.pen);
            switch(cpoint.type){
            case DrawPen:{
                p->drawPoint(cpoint.start);
            }break;
            case DrawLine:{
                p->drawLine(cpoint.start,cpoint.end);
            }break;
            default:break;
            }
        }
        p->end();
        if(size!=m_editImage.size())
            m_editImage = m_editImage.scaled(size);

        m_saveInProgress = false;
        update();
    }
}

QString ImageCanvas::freeFilename()
{
    qDebug() << __PRETTY_FUNCTION__;
    QString fn;
    int count=0;
    int subcount = 0;
    QString prefix("example");

    QString path(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation));
    path = "e:/"+path.split('/',QString::SkipEmptyParts).last();
    QDirIterator di(path,QStringList() << "*.jpg",QDir::Files);
    while(di.hasNext()){
        QString name = di.next();
        QFileInfo fi(name);
        name = fi.baseName();
        if(QString::compare(prefix,name,Qt::CaseInsensitive)==0)
            count++;

        QStringList list = name.split('_');
        if(list.count()>1){
            if(QString::compare(prefix,list.at(0),Qt::CaseInsensitive)==0){
                if(subcount<list.at(1).toInt())
                    subcount = list.at(1).toInt();
            }
        }
    }

    if(subcount && !count)
        count = 1;
    count+=subcount;

    if(count)
        fn = prefix+"_"+QString::number(count)+".jpg";
    else
        fn = prefix+".jpg";

    return fn;
}
